package autokeyboard.gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

import autokeyboard.data.KeyCharMask;
import autokeyboard.data.KeyCharName;
import autokeyboard.data.PicturePanel;

@SuppressWarnings({ "serial" })
public class KeyStrokeDialog extends JDialog
{
	private JPanel			panelOption		= new JPanel();
	private JPanel			panelButton		= new JPanel();

	private JPanel			panelLabel		= new JPanel();
	private JPanel			panelTextField	= new JPanel();

	private JLabel			lblKeyStroke	= new JLabel();
	private JLabel			lblDelay		= new JLabel();

	private JButton			btnOK			= new JButton();
	private JButton			btnCancel		= new JButton();

	private JTextField		tfKeyStroke		= new JTextField();
	private JTextField		tfDelay			= new JTextField();

	private KeyCharMask		mask			= new KeyCharMask();
	private KeyCharName		keyName			= new KeyCharName();

	private PicturePanel	picPanel		= new PicturePanel();

	private Object[]		list;
	private Object[]		listTemp;
	private boolean			changed			= false;

	public KeyStrokeDialog(JFrame frame, Object[] list)
	{
		super(frame, true);

		this.list = list;

		initComponent();
		dialogProperties(frame);
		setTextFieldDefaultValue();
	}

	private void dialogProperties(JFrame frame)
	{
		this.setSize(250, 190);
		this.setResizable(false);
		this.setTitle("KeyStroke Setting");
		this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		this.setIconImage(frame.getIconImage());
		this.setLocationRelativeTo(frame);
	}

	private void initComponent()
	{
		setComponentsProperties();
		setMainLayout();
		setLayoutPanelOption();
		setLayoutPanelButton();
		setLayoutPanelLabel();
		setLayoutPanelTextField();

		buttonEvent();
		keyEvent();
		focusEvent();
	}

	private void setMainLayout()
	{
		this.add(picPanel);
		picPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
		picPanel.add(panelOption);
		picPanel.add(panelButton);
		
		picPanel.path = "/Background/ControlsSetting.png";
		picPanel.repaint();
	}

	private void setLayoutPanelOption()
	{
		panelOption.setLayout(new FlowLayout(FlowLayout.CENTER));
		panelOption.setBorder(BorderFactory.createTitledBorder(""));
		panelOption.setOpaque(false);
		panelOption.setPreferredSize(new Dimension(240, 100));

		panelOption.add(panelLabel);
		panelOption.add(panelTextField);
	}

	private void setLayoutPanelButton()
	{
		panelButton.setLayout(new FlowLayout(FlowLayout.RIGHT));
		panelButton.setPreferredSize(new Dimension(250, 45));
		panelButton.setOpaque(false);
		panelButton.add(btnOK);
		panelButton.add(btnCancel);
	}

	private void setLayoutPanelLabel()
	{
		panelLabel.setLayout(new FlowLayout(FlowLayout.LEFT));
		panelLabel.setPreferredSize(new Dimension(90, 80));
		panelLabel.setOpaque(false);

		panelLabel.add(lblKeyStroke);
		panelLabel.add(lblDelay);
	}

	private void setLayoutPanelTextField()
	{
		panelTextField.setLayout(new FlowLayout(FlowLayout.LEFT));
		panelTextField.setPreferredSize(new Dimension(110, 80));
		panelTextField.setOpaque(false);

		panelTextField.add(tfKeyStroke);
		panelTextField.add(tfDelay);
	}

	private void setComponentsProperties()
	{
		lblKeyStroke.setFont(new Font("Calibri", 1, 20));
		lblKeyStroke.setForeground(Color.white);
		lblKeyStroke.setText("KeyStroke");
		lblDelay.setFont(lblKeyStroke.getFont());
		lblDelay.setForeground(Color.white);
		lblDelay.setText("Delay");

		tfKeyStroke.setFont(new Font("Calibri", 0, 16));
		tfKeyStroke.setPreferredSize(new Dimension(100, 25));
		tfKeyStroke.setEditable(false);
		tfKeyStroke.setBackground(Color.white);

		tfDelay.setFont(tfKeyStroke.getFont());
		tfDelay.setPreferredSize(new Dimension(100, 25));

		btnOK.setFont(new Font("Calibri", 0, 20));
		btnOK.setText("OK");
		btnCancel.setFont(new Font("Calibri", 0, 20));
		btnCancel.setText("Cancel");
	}

	/**
	 * This method will add event to all your button when button is pressed
	 */
	private void buttonEvent()
	{
		btnOK.addActionListener(new ActionListener()
		{
			@Override
			public void actionPerformed(ActionEvent e)
			{
				updateValueToList();
				dispose();
			}
		});

		btnCancel.addActionListener(new ActionListener()
		{

			@Override
			public void actionPerformed(ActionEvent e)
			{
				dispose();
			}
		});
	}

	/**
	 * This method will add event to all component when press key
	 */
	private void keyEvent()
	{
		JTextField listTf[] = { tfKeyStroke, tfDelay };
		JButton[] listButton = { btnOK, btnCancel };

		for (final JButton button : listButton)
		{
			button.addKeyListener(new KeyAdapter()
			{
				@Override
				public void keyPressed(KeyEvent evt)
				{
					if (evt.getKeyCode() == KeyEvent.VK_ESCAPE) dispose();
				}
			});
		}

		for (final JTextField textField : listTf)
		{
			textField.addKeyListener(new KeyAdapter()
			{
				@Override
				public void keyPressed(KeyEvent evt)
				{
					if (evt.getKeyCode() == KeyEvent.VK_ESCAPE) dispose();
				}
			});
		}

		tfKeyEvent();
	}

	/**
	 * This method will add key event for your text field
	 */
	private void tfKeyEvent()
	{
		tfKeyStroke.addKeyListener(new KeyAdapter()
		{
			@Override
			public void keyPressed(KeyEvent evt)
			{
				getOnlyOneLetter(evt);
				updateValueTemp(evt);
			}

		});

		tfDelay.addKeyListener(new KeyAdapter()
		{
			@Override
			public void keyPressed(KeyEvent evt)
			{
				/**
				 * Check whether your input is a number. If it is not a number.
				 * It will delete your input
				 */
				if (!isValidNumber(tfDelay.getText()) && tfDelay.getText().length() != 0)
				{
					tfDelay.setText(tfDelay.getText().substring(0, tfDelay.getText().length() - 1));
				}
			}

			@Override
			public void keyReleased(KeyEvent evt)
			{
				/**
				 * Check whether your input is a number. If it is not a number.
				 * It will delete your input
				 */
				if (!isValidNumber(tfDelay.getText()) && tfDelay.getText().length() != 0)
				{
					tfDelay.setText(tfDelay.getText().substring(0, tfDelay.getText().length() - 1));
				}
				else if (isValidNumber(tfDelay.getText()) && tfDelay.getText().length() != 0)
				{
					try
					{
						int number = Integer.parseInt(tfDelay.getText());
						if (number < 1)
						{
							tfDelay.setText("1");
						}
					} catch (Exception ex)
					{
					}
				}
			}
		});
	}

	/**
	 * This method will check whether your input is number or not.
	 * 
	 * @param text
	 * @return
	 */
	private boolean isValidNumber(String text)
	{
		if (text.length() != 0)
		{
			char[] list = text.toCharArray();
			for (char item : list)
			{
				if (!Character.isDigit(item)) return false;
			}
		}
		return true;
	}

	/**
	 * This method will get only only one letter when you press any key
	 */
	private void getOnlyOneLetter(KeyEvent evt)
	{
		String temp = mask.keyCharMarsk(evt);
		tfKeyStroke.setText(temp);
	}

	/**
	 * This method will set your text field with keyStroke and keyStrokeDelay of
	 * which row your double clicked
	 */
	private void setTextFieldDefaultValue()
	{
		tfKeyStroke.setText(list[2].toString());
		tfDelay.setText(list[3].toString());
	}

	/**
	 * This method will return a edited list object
	 * 
	 * @return edited object list
	 */
	public Object[] getNewObjectList()
	{
		return this.list;
	}

	/**
	 * This method will update your current object list
	 */
	private void updateValueToList()
	{
		updateValueTemp();
		list = listTemp;
	}

	/**
	 * This method will update what you've edited to listTemp
	 * 
	 * @param evt
	 */
	private void updateValueTemp(KeyEvent evt)
	{
		changed = true;
		Object[] item = { Integer.parseInt(list[0].toString()), "Key Press " + keyCharShow(evt), keyChar(evt), Integer.parseInt(tfDelay.getText()) };
		listTemp = item;
	}

	/**
	 * This method will update what you've edited to listTemp
	 */
	private void updateValueTemp()
	{
		if (changed)
		{
			Object[] item = { Integer.parseInt(list[0].toString()), listTemp[1].toString(), listTemp[2].toString(), Integer.parseInt(tfDelay.getText()) };
			listTemp = item;
		}
		else
		{
			Object[] item = { Integer.parseInt(list[0].toString()), list[1].toString(), list[2].toString(), Integer.parseInt(tfDelay.getText()) };
			listTemp = item;
		}
	}

	/**
	 * This method will return a key mask with your input key
	 * <p>
	 * It use KeyEvent to get your input key
	 * 
	 * @param evt
	 * @return
	 */
	private String keyChar(KeyEvent evt)
	{
		return mask.keyCharMarsk(evt);
	}

	/**
	 * This method will return your key name with your input key
	 * <p>
	 * It use KeyEvent to get your input key
	 * 
	 * @param evt
	 * @return
	 */
	private String keyCharShow(KeyEvent evt)
	{
		return keyName.keyFullName(evt);
	}
	
	/**
	 * This method will addFocusListener for tfDelay
	 * <p>
	 * When tfDelay is lost focus it will check whether tfDelay had a value or not.
	 * Unless it had a value this will set the default value is 50 to that text field
	 */
	private void focusEvent()
	{
		tfDelay.addFocusListener(new FocusAdapter()
		{
			@Override
			public void focusLost(FocusEvent e)
			{
				if(tfDelay.getText().length() == 0)
				{
					tfDelay.setText("50");
				}
			}
			
			@Override
			public void focusGained(FocusEvent e)
			{
				tfDelay.setSelectionStart(0);
				tfDelay.setSelectionEnd(tfDelay.getText().length());
			}
		});
	}

}
